using System;
using System.ComponentModel;
using System.Collections.Generic;

namespace ReportMaintenanceUtility
{
	public abstract class GenericBase<T> : IStateManagement<T>, INotifyPropertyChanged
	{
		//misc abstract methods...
		protected bool _initializing = false;
		protected abstract void Initialize();
		public abstract bool EqualTo(T other);

		//reference to the underlying deserialized object
		public abstract object CreateSeedCopy();

		#region STATE MANAGEMENT

		//used to create deep copies of an object's original state...
		protected T _copy = default(T);
		public abstract T CreateDeepCopy();
		protected void CopyListeners(GenericBase<T> other)
		{
			this.PropertyChanged = other.PropertyChanged;
		}

		//indicates if the state of the object has changed but not been saved...
		protected bool _isDirty = false;
		[Bindable(false)] public bool IsDirty
		{
			get { return this._isDirty; }
		}
		public void ClearListeners()
		{
			this.PropertyChanged = null;
		}
		
		//first method called in the property setter of all derived classes...
		public void PrepStateChange(string propertyName)
		{
			if (!this._initializing)
			{
				if (!this._isDirty)
				{
					this._copy = this.CreateDeepCopy();
					this._isDirty = true;
				}
				this.NotifyPropertyChanged(propertyName);
			}
		}

		//called once SaveState() is successfully executed...
		protected void ClearState()
		{
			this._copy = default(T);
			this._isDirty = false;
		}

		//these methods are specific to each derived class and encompass modifying the structure of the underlying
		//seed object to match the state of the current object in preparation for serializing the report back to XML
		//or returning the object to its premodified state
		public abstract List<ChangeLog> SaveState();
		public abstract void RestoreState();

		#endregion

		
		#region EVENT NOTIFICATION HANDLING

		public event PropertyChangedEventHandler PropertyChanged;
		protected void NotifyPropertyChanged(String info)
		{
			if (this.PropertyChanged != null)
			{
				this.PropertyChanged(this, new PropertyChangedEventArgs(info));
			}
		}
		protected void PropertyChangedListener(object sender, PropertyChangedEventArgs args)
		{
			if (this != sender)
			{
				this.PrepStateChange(args.PropertyName);
			}
		}
		#endregion
	}
}
